<?php
class system_session_namespace extends system_session_abstract implements IteratorAggregate {
	
	const SINGLE_INSTANCE = true;
	protected $_namespace = "default";
	protected static $_namespaceLocks = array();
	protected static $_singleInstances = array();
	
	public static function resetSingleInstance($namespaceName = null) {
		if($namespaceName != null) {
			if(array_key_exists($namespaceName, self::$_singleInstances)) {
				unset(self::$_singleInstances[$namespaceName]);
			}
			return;
		}
		self::$_singleInstances = array();
		return;
	}
	
	public function __construct($namespace = 'Default', $singleInstance = false) {
		if($namespace === '') {
			throw new system_session_exception('Session namespace must be a non-empty string.');
		}
		if($namespace[0] == "_") {
			throw new system_session_exception('Session namespace must not start with an underscore.');
		}
		if(preg_match('#(^[0-9])#i', $namespace[0])) {
			throw new system_session_exception('Session namespace must not start with a number.');
		}
		if(isset(self::$_singleInstances[$namespace])) {
			throw new system_session_exception("A session namespace object already exists for this namespace ('$namespace'), and no additional accessors (session namespace objects) for this namespace are permitted.");
		}
		if($singleInstance === true) {
			self::$_singleInstances[$namespace] = true;
		}
		$this->_namespace = $namespace;
		system_session::start(array());
		if(self::$_readable === false) {
			throw new system_session_exception(self::_THROW_NOT_READABLE_MSG);
		}
	}
	
	public function getIterator() {
		return new ArrayObject(parent::_namespaceGetAll($this->_namespace));
	}
	
	public function lock() {
		self::$_namespaceLocks[$this->_namespace] = true;
	}
	
	public function unlock() {
		unset(self::$_namespaceLocks[$this->_namespace]);
	}
	
	public static function unlockAll() {
		self::$_namespaceLocks = array();
	}
	
	public function isLocked() {
		return isset(self::$_namespaceLocks[$this->_namespace]);
	}
	
	public function unsetAll() {
		return parent::_namespaceUnset($this->_namespace);
	}
	
	public function &__get($name) {
		if($name === '') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}
		return parent::_namespaceGet($this->_namespace, $name);
	}
	
	public function __set($name, $value) {
		if(isset(self::$_namespaceLocks[$this->_namespace])) {
			throw new system_session_exception('This session/namespace has been marked as read-only.');
		}
		if($name === '') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}
		if(parent::$_writable === false) {
			throw new system_session_exception(parent::_THROW_NOT_WRITABLE_MSG);
		}
		$name = (string) $name;
		$_SESSION[$this->_namespace][$name] = $value;
	}
	
	public function __isset($name) {
		if($name === '') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}
		return parent::_namespaceIsset($this->_namespace, $name);
	}
	
	public function __unset($name) {
		if($name === '') {
			throw new system_session_exception("The '$name' key must be a non-empty string");
		}		
		return parent::_namespaceUnset($this->_namespace, $name);
	}
	
	public function setExpirationSeconds($seconds, $variables = null) {
		if(parent::$_writable === false) {
			throw new system_session_exception(parent::_THROW_NOT_WRITABLE_MSG);
		}
		if($seconds <= 0) {
			throw new system_session_exception('Seconds must be positive.');
		}
		$expire = time() + $seconds;
		if(isset($_COOKIE[session_name()])) {
			$cookie_params = session_get_cookie_params();			
			setcookie(session_name(), $_COOKIE[session_name()], $expire, $cookie_params['path'], $cookie_params['domain'], $cookie_params['secure']);
		}
		if($variables === null) {
			$_SESSION['__SYSTEM'][$this->_namespace]['ENT'] = $expire;
		} else {
			if(is_string($variables)) {
				$variables = array($variables);
			}
			foreach($variables as $variable) {
				if(!empty($variable)) {
					$_SESSION['__SYSTEM'][$this->_namespace]['ENVT'][$variable] = $expire;
				}
			}
		}
	}
	
	public function getNamespace() {
		return $this->_namespace;
	}
}
